package com.franklin.ideaplugin.maphelper.resolver.impl.map.json.fastjson;

import cn.hutool.core.collection.CollectionUtil;
import com.franklin.ideaplugin.api.beans.declaration.IDeclaration;
import com.franklin.ideaplugin.api.utils.psi.PsiExpressionUtils;
import com.franklin.ideaplugin.api.utils.psi.PsiTreeUtils;
import com.franklin.ideaplugin.maphelper.beans.colmember.IColMember;
import com.franklin.ideaplugin.maphelper.col.declaration.IColDeclaration;
import com.franklin.ideaplugin.maphelper.col.method.IColQueryMethod;
import com.franklin.ideaplugin.maphelper.col.operation.impl.map.FastJson1JsonObjectReadWriteOperation;
import com.franklin.ideaplugin.maphelper.resolver.impl.collection.CollectionMemberResolverFactory;
import com.franklin.ideaplugin.maphelper.resolver.impl.map.CollectionMapMemberResolver;
import com.franklin.ideaplugin.maphelper.resolver.impl.map.InnerMapMapMethodCallExpressionMemberResolver;
import com.franklin.ideaplugin.maphelper.resolver.impl.map.MapNewExpressionMemberResolver;
import com.franklin.ideaplugin.maphelper.utils.FastJsonUtils;
import com.franklin.ideaplugin.maphelper.utils.PsiColUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;

import java.util.*;

/**
 * 链式调用的内部JSON解析
 *
 * @author Ye Junhui
 * @since 2024/3/22
 */
public class FastJsonInnerJsonMethodChainMemberResolver extends InnerMapMapMethodCallExpressionMemberResolver {

    public final static FastJsonInnerJsonMethodChainMemberResolver INSTANCE = new FastJsonInnerJsonMethodChainMemberResolver();

    /**
     * 查询方法
     */
    private final static Set<IColQueryMethod> FAST_JSON_QUERY_METHODS = new FastJson1JsonObjectReadWriteOperation().getQueryMethods();

    @Override
    public boolean supports(IColDeclaration colDeclaration) {
        IDeclaration declaration = colDeclaration.getDeclaration();
        PsiType psiType = declaration.getPsiType();
        if (!PsiClassType.class.isInstance(psiType)) {
            return false;
        }

        //链式调用
        PsiMethodCallExpression psiMethodCallExpression = declaration.getCreateExpression(PsiMethodCallExpression.class);
        if (Objects.isNull(psiMethodCallExpression)) {
            return false;
        }

        PsiClassType psiClassType = (PsiClassType) psiType;
        PsiClass psiClass = psiClassType.resolve();
        if (!FastJsonUtils.isJsonObjectClass(psiClass)) {
            return false;
        }

        //操作
        IColQueryMethod colQueryMethod = getColQueryMethod(psiMethodCallExpression);

        return Objects.nonNull(colQueryMethod);
    }

    @Override
    public Collection<IColMember> resolveColMembers(PsiElement psiExpression, IColDeclaration colDeclaration) {
        //结果
        Set<IColMember> result = Sets.newLinkedHashSet();

        //当前代码块
        Collection<IColMember> currentMembers = MapNewExpressionMemberResolver.INSTANCE.resolveColMembers(psiExpression, colDeclaration);
        CollectionUtil.addAll(result, currentMembers);

        //调用链
        //链式调用
        PsiMethodCallExpression psiMethodCallExpression = colDeclaration.getDeclaration().getCreateExpression(PsiMethodCallExpression.class);
        if (Objects.isNull(psiMethodCallExpression)) {
            return result;
        }

        //所有方法调用链(从后往前)
        Collection<PsiMethodCallExpression> psiMethodCallExpressions = PsiTreeUtil.collectElementsOfType(psiMethodCallExpression, PsiMethodCallExpression.class);
        //翻转
        Deque<PsiMethodCallExpression> deque = Lists.newLinkedList();
        psiMethodCallExpressions.forEach(deque::addFirst);

        //跟节点
        PsiMethodCallExpression root = deque.pop();

        //判断root类型
        PsiIdentifier rootTarget = PsiTreeUtil.findChildOfType(root, PsiIdentifier.class);
        PsiExpression callerExpression = PsiTreeUtil.getParentOfType(rootTarget, PsiExpression.class);
        IColDeclaration rootDeclaration = PsiColUtils.findColExpressionDeclaration(callerExpression);
        if (Objects.isNull(rootDeclaration)){
            return result;
        }
        PsiType psiType = rootDeclaration.getDeclaration().getPsiType();
        PsiClassType psiClassType = (PsiClassType) psiType;
        PsiClass psiClass = psiClassType.resolve();
        Collection<IColMember> colMembers = Collections.emptyList();
        if (FastJsonUtils.isJsonArrayClass(psiClass)) {
            colMembers = CollectionMapMemberResolver.INSTANCE.resolveColMembers(callerExpression,rootDeclaration);
        } else {
            colMembers = super.resolveColMembers(root, colDeclaration);
        }
        Collection<IColMember> tempMembers = colMembers;

        //开始匹配
        while (CollectionUtil.isNotEmpty(deque)) {
            PsiMethodCallExpression pop = deque.pop();
            //获取查询方法
            IColQueryMethod colQueryMethod = getColQueryMethod(pop);
            if (Objects.isNull(colQueryMethod)) {
                break;
            }
            //调用目标
            PsiExpressionList psiExpressionList = PsiTreeUtils.findLastChild(pop, PsiExpressionList.class);
            if (Objects.isNull(psiExpressionList)) {
                break;
            }
            PsiExpression targetExpression = psiExpressionList.getExpressions()[colQueryMethod.getQueryTargetIndex()];
            String targetKey = targetExpression.getText();

            //匹配
            IColMember matchMember = CollectionUtil.findOne(tempMembers, colMember -> colMember.getKeyText().equals(targetKey));
            if (Objects.nonNull(matchMember)) {
                tempMembers = matchMember.getChildren(getColMemberResolverFactory());
            } else {
                break;
            }
        }

        //写入结果
        CollectionUtil.addAll(result, tempMembers);

        return result;
    }

    /**
     * 寻找查询方法
     *
     * @param psiMethodCallExpression
     * @return
     */
    private IColQueryMethod getColQueryMethod(PsiMethodCallExpression psiMethodCallExpression) {
        //寻找最后一个调用方法
        PsiIdentifier psiIdentifier = PsiTreeUtils.findLastChild(psiMethodCallExpression, PsiIdentifier.class);
        if (Objects.isNull(psiIdentifier)) {
            return null;
        }
        String text = psiIdentifier.getText();
        for (IColQueryMethod fastJsonQueryMethod : FAST_JSON_QUERY_METHODS) {
            if (fastJsonQueryMethod.match(text)) {
                return fastJsonQueryMethod;
            }
        }
        return null;
    }
}
